////////////////////////////////////////////////////////////////////////////////
// $Id$
// Copyright (C) 2008
// Emory Merryman
// ree9opdz@gmail.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
////////////////////////////////////////////////////////////////////////////////

package com . linglingqi . factories ;

/**
 * Makes Factories using reflection.
 *
 * @author $Author$
 * @version $Revision$
 **/
public final class ConstructorFactories
{
    /**
     * Embedded Copyright Notice.
     **/
    public static final java . lang . String EMBEDDED_COPYRIGHT =
        "Copyright (C) 2008, Emory Merryman, ree9opdz@gmail.com" ;

    /**
     * Hide the no-args constructor.
     **/
    private ConstructorFactories ( )
    {
	super ( ) ;
    }

    /**
     * Makes a Factory based on the specified constructor.
     *
     * @param constructor the specified constructor
     * @param eClass the type of error the factory can throw
     * @param <R> the type of thing this factory makes
     * @param <E> the type of error the factory can throw
     * @return a Factory
     **/
    public static final
	< R ,
	E extends java . lang . Exception >
		  Factory1 < R , java . lang . Object [ ] , E >
		  instance
		  (
		   final java . lang . reflect . Constructor < R > constructor ,
		   final java . lang . Class < E > eClass
		   )
    {
	final Factory1 < R , java . lang . Object [ ] , E > factory =
	    new Factory1 < R , java . lang . Object [ ] , E > ( )
	    {
		public final R make
		( final java . lang . Object [ ] parameters )
		throws E
		{
		    R r = null ;
		    try
			{
			    r = constructor . newInstance ( parameters ) ;
			}
		    catch ( final java . lang . Exception cause )
			{
			    final E e = eClass . cast ( cause ) ;
			    throw ( e ) ;
			}
		    return ( r ) ;
		}
	    } ;
	return ( factory ) ;
    }

    /**
     * Makes a Factory based on reflection..
     *
     * @param rClass the return type of the factory
     * @param cClass the return type of the constructor
     * @param eClass the type of error this factory can throw
     * @param <R> the return type of the factory
     * @param <C> the constructor type
     * @param <E> the type of error this factory can throw
     * @return a Factory
     **/
    public static final
	< R , C extends R , E extends java . lang . Exception >
			Factory0 < R , E >
			instance
			(
			 final java . lang . Class < R > rClass ,
			 final java . lang . Class < C > cClass ,
			 final java . lang . Class < E > eClass
			 )
	throws java . lang . NoSuchMethodException ,
	       java . lang . SecurityException
    {
	final java . lang . Class [ ] parameterTypes = { } ;
	final java . lang . reflect . Constructor < C > constructor =
	    cClass . getDeclaredConstructor ( parameterTypes ) ;
	final Factory1 < C , java . lang . Object [ ] , E > innerFactory =
	    instance ( constructor , eClass ) ;
	final java . lang . Class [ ] parameters = null ;
	final Factory0 < R , E > factory = new Factory0 < R , E > ( )
	{
	    public final R make ( ) throws E
	    {
		final R r = innerFactory . make ( parameters ) ;
		return ( r ) ;
	    }
	} ;
	return ( factory ) ;
    }

    /**
     * Makes a Factory based on reflection..
     *
     * @param rClass the return type of the factory
     * @param cClass the return type of the constructor
     * @param p1Class the type of the first parameter
     * @param eClass the type of error this factory can throw
     * @param <R> the return type of the factory
     * @param <C> the constructor type
     * @param <P1> the type of the first parameter
     * @param <E> the type of error this factory can throw
     * @return a Factory
     **/
    public static final
	< R ,
	C extends R ,
		  P1 ,
		  E extends java . lang . Exception >
			    Factory1 < R , P1, E >
			    instance
			    (
			     final java . lang . Class < R > rClass ,
			     final java . lang . Class < C > cClass ,
			     final java . lang . Class < P1 > p1Class ,
			     final java . lang . Class < E > eClass
			     )
	throws java . lang . NoSuchMethodException ,
	       java . lang . SecurityException
    {
	final java . lang . Class [ ] parameterTypes = { } ;
	final java . lang . reflect . Constructor < C > constructor =
	    cClass . getDeclaredConstructor ( parameterTypes ) ;
	final Factory1 < C , java . lang . Object [ ] , E > innerFactory =
	    instance ( constructor , eClass ) ;
	final Factory1 < R , P1 , E > factory = new Factory1 < R , P1 , E > ( )
	{
	    public final R make ( final P1 p1 ) throws E
	    {
		final java . lang . Object [ ] parameters = { p1 } ;
		final R r = innerFactory . make ( parameters ) ;
		return ( r ) ;
	    }
	} ;
	return ( factory ) ;
    }
}
